package org.springframework.aop;

import org.springframework.aop.framework.AdvisorChainFactory;
import org.springframework.aop.framework.DefaultAdvisorChainFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author zqc
 * @date 2022/12/16
 */
public class AdvisedSupport {
	//和我们之前学的一样，不过在spring源码里，由于aop有两种实现，所以我们要考虑是jdk的还是cglib的
	//是否使用cglib代理
	private boolean proxyTargetClass = true;


	//实际上我们一般也就存这俩
	private TargetSource targetSource;
	//源目标对象
	private MethodMatcher methodMatcher;
	//匹配的方法



	private transient Map<Integer, List<Object>> methodCache;

	AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();


	//之前我们这里都是一个成员变量，这里变成一个list集合了。这就是拦截器链。存很多的拦截器的
	private List<Advisor> advisors = new ArrayList<>();


	public AdvisedSupport() {
		this.methodCache = new ConcurrentHashMap<>(32);
	}
	public boolean isProxyTargetClass() {
		return proxyTargetClass;
	}

	public void setProxyTargetClass(boolean proxyTargetClass) {
		this.proxyTargetClass = proxyTargetClass;
	}

	public void addAdvisor(Advisor advisor) {
		advisors.add(advisor);
	}

	public List<Advisor> getAdvisors() {
		return advisors;
	}

	public TargetSource getTargetSource() {
		return targetSource;
	}

	public void setTargetSource(TargetSource targetSource) {
		this.targetSource = targetSource;
	}


	public MethodMatcher getMethodMatcher() {
		return methodMatcher;
	}

	public void setMethodMatcher(MethodMatcher methodMatcher) {
		this.methodMatcher = methodMatcher;
	}
	/**
	 * 用来返回方法的拦截器链
	 */
	//把拦截器链拿过来
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
		//这里面有一个SpringAOP缓存的概念，如果这个方法来过，hash值存入缓存（作为key），把他的advisors（拦截器链）作为value
		// Map<Integer, List<Object>> methodCache;


		Integer cacheKey=method.hashCode();
		//看看这个方法之前是否来过（增强过），有没有他的拦截器
		List<Object> cached = this.methodCache.get(cacheKey);


		if (cached == null) {
			//如果之前没来过，得到拦截器链。这里应该有两个拦截器（之前存入过两次advisor和advisor1）
			//不过这个拦截器链，返回的都是你方法要的，怎么判断。我们看看
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			this.methodCache.put(cacheKey, cached);//找到后存入进去key-value形式
		}
		return cached;
	}
}
